package com.asa.numanaly;

import java.util.ArrayList;
import java.util.List;

import com.asa.HanShu;
import com.asa.chart.MathPointUtil;
import com.asa.chart.work.AlgoVisualizer;
import com.asa.fushu.bean.Eulerformula;
import com.asa.fushu.bean.Fushu;
import com.asa.utils.Calculate;
import com.asa.utils.MathUtils;

/**
 * 傅里叶变换及应用
 * 
 * 如果这里面涉及到复数部分，会让我感觉比较难
 * 
 * Math.exp(i*x) = Math.cos(x)+ i*Math.sin(x)
 * 这里的这个i是无法表达的
 * 但我 是有办法处理它的
 * 
 * 
 * 我期望以此为契机，将复数域上的东西表达好
 * 
 * 
 * @author asa
 *
 */
public class Fourier {
	
	
	
	public static void main(String[] args) {
		final int sceneWidth = 900;
		final int sceneHeight = 900;
		int N = 10;
		List<double[][]> zhi = fourier_jishu();
//		List<double[][]> zhi = new ArrayList<double[][]>();//函数的线簇
		HanShu hanshu = new HanShu() {
			
			@Override
			public double hanshu(double t, double x) {
				// TODO Auto-generated method stub
				return 0;
			}
			
			@Override
			public double hanshu(double x) {
				// TODO Auto-generated method stub
//				return x - 2*Math.pow(x, 2) + 3*Math.pow(x, 3) - 4*Math.pow(x, 4);
				return Math.sin(x)*Math.sin(x);
//				return Math.exp(-Math.PI*x*x);//高斯 正态分布 钟形图
				
//				return Math.exp(-Math.PI*x*x/2)/Math.pow(2*Math.PI, 0.5);//高斯函数 微分结果
//				return 0.8*Math.pow(x,0.8-1);

			}
		};
//		double[][] hanshupointf = MathPointUtil.hanshupoint(hanshu,0.01,10);
//		zhi.add(hanshupointf);
		
//		System.out.println(Calculate.hanshujifen2(-3,3, hanshu));
		
		AlgoVisualizer algoVisualizer = new AlgoVisualizer(sceneWidth, sceneHeight, N,zhi,50);
		
		
		
		Fushu[] a = new Fushu[4];
		a[0] = new Fushu(1, 0);
		a[1] = new Fushu(1, 1);
		a[2] = new Fushu(-1, 0);
		a[3] = new Fushu(-1, 1);

		
		Fushu[] fft = FFT(a);
		System.out.println(fft.length);
		for (int i = 0; i < fft.length; i++) {
			fft[i].shownumber();
		}
		
		
		
	}

	
	
	/*************卷积****************/
	/**
	 * 	卷积这个名字在很多地方都有出现
	 * 	离散数学里面
	 * 	数学分析里面
	 * 	傅里叶里面
	 * 	常微分方程里面
	 * 	信息论里面
	 * 	神经网络里面
	 * 
	 */
	
	/**
	 * 	离散里面
	 * 		
	 * 	比如两个数组，都是1到20
	 * 	我们要算两者各选出一个数，组成起来是30的组合概率	
	 * 	P(30) = P1(10)*P2(20) + P1(11)*P2(19) + P1(12)*P2(18) +...+P1(20)*P2(10)	
	 * 	
	 * 	会发现P1和P2里面的值之和，是一个定值
	 * 	那么可以得出一个函数
	 * 		y(n) = (累加)x(i)*h(n-i) 
	 * 
	 * 
	 * 
	 * 
	 */
	
	/**
	 * 	对离散的情况进行扩展，扩展到连续的情况下
	 * 
	 * 	可以	看做
	 * 	y(n) = （积分）x(t)*h(n-t) 	0到n的定积分
	 * 	
	 * 
	 * 	特别地
	 * 		在概率论里面
	 * 			两个事件独立的时候，y(n) = （积分）x(t)*h(n-t) 
	 * 			而如果是相关y(n) = （积分）x(t,n-t)	联合积分
	 * 
	 * 
	 * 
	 */
	
	
	
	
	
	
	
	
	
	
	

	/*****************************************2傅里叶级数到傅里叶变换************************************************************/

	/**
	 * 傅里叶级数到傅里叶变换
	 * 是周期性的到非周期性的变换
	 * 
	 * 其实有一种思路，就是计算函数的周期，从原来的固定周期设置为负无穷大到正无穷大（对周期计算进行延拓）
	 * 这样不就是非周期的傅里叶级数改进成了非周期的傅里叶变换了吗
	 * 但实际上这种做法是行不通的，无穷积分如果函数不在正无穷和负无穷这两端都收敛，就会算出个无穷大，这个是无法表达的
	 * 
	 * 如果这个函数在一段范围内是收敛的，有一个固定的积分值，而我们用一个大于，或者说一定范围的x来限定这个函数，用来计算函数的积分
	 * 那么：系数趋近于无穷时候，傅里叶级数的系数项会趋近于0，这个也是不行，真诡异
	 * 
	 * 
	 * 
	 * 时延性、尺度变化，卷积
	 * 	时延性，函数的t变量加减变化，导致函数的移动，体现出时延性
	 * 	尺度变化，函数的t变量成除变化，导致函数的放缩，体现出尺度变化
	 * 	两个函数相乘，这个叫卷积，我很迷惑这个名字的含义，因为我在矩阵，还有机器学习里面也包含了这个名称
	 */
	
	
	/**
	 * 快速傅里叶变换，这个我直接在算法导论里面去找的	ALGORITHMS这本书 p932
	 * @param a	这个a的长度要求是2的次方
	 * @return
	 */
	public static Fushu[] FFT(Fushu[] a) {
		
		int n = a.length;
//		System.out.println(n);
		if (n==1) {
			return a;
		}
		
		Fushu wn = Eulerformula.wmn(1, n);
		Fushu w = new Fushu(1, 0);
		
		Fushu[] a0 = new Fushu[n/2];
		Fushu[] a1 = new Fushu[n/2];
		for (int i = 0; i < a0.length; i++) {
			a0[i] = a[i*2];
		}
		for (int i = 0; i < a1.length; i++) {
			a1[i] = a[i*2+1];
		}
		
		Fushu[] y0 = FFT(a0);
		Fushu[] y1 = FFT(a1);
		
		Fushu[] y = new Fushu[n];
		for (int k = 0; k < n/2; k++) {
			
			y[k] = y0[k].add(w.mul(w, y1[k]));
			
			y[k + n/2] = y0[k].sub(w.mul(w, y1[k]));
			w = w.mul(w, wn);
		}
		
		
		return y;
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
/*****************************************1傅里叶级数************************************************************/

	/**
	 * 傅里叶级数的测试
	 * @return
	 */
	private static List<double[][]> fourier_jishu() {
		//		List<double[][]> zhi = testnorm();
				
				
		//		double[] x = { 0.24, 0.65, 0.95, 1.24, 1.73, 2.01, 2.23, 2.52, 2.77,
		//				2.99 };
		//		double[] y = { 0.23, -0.26, -1.10, -0.45, 0.27, 0.10, -0.29, 0.24,
		//				0.56, 1.00 };
		//		double[] x = { 0.24, 0.65, 0.95, 1.24, 1.73, 2.01 };
		//		double[] y = { 0.23, -0.26, -1.10, -0.45, 0.27, 0.10 };
		//		double[] x = new double[]{8.1,8.3,8.6,8.7};
		//		double[] y = new double[]{16.99410,17.56492,18.50515,18.82091};
				
		
		//		double[] x = {0.9,1.3,1.9,2.1,2.6,3.0,3.9,4.4,4.7,5.0,6.0,7.0,8.0,9.2,10.5,11.3,11.6,12.0,12.6,13.0,13.3};
		//		double[] y = {1.3,1.5,1.85,2.1,2.6,2.7,2.4,2.15,2.05,2.1,2.25,2.3,2.25,1.95,1.4,0.9,0.7,0.6,0.5,0.4,0.25};
				
				
				List<double[][]> zhi = new ArrayList<double[][]>();//函数的线簇
		
		//		double[] norm = H.Norm(x,y);.
		//		HanShu norm2hanshu = H.Norm2hanshu(norm);
		//		double[][] hanshupoint = MathPointUtil.hanshupoint(norm2hanshu);
		//		zhi.add(hanshupoint);
		//		double[][] x_y2xy = MathPointUtil.x_y2xy(x, y);
		//		zhi.add(x_y2xy);
				
				HanShu hanshu = new HanShu() {
					
					@Override
					public double hanshu(double t, double x) {
						// TODO Auto-generated method stub
						return 0;
					}
					
					@Override
					public double hanshu(double x) {
						// TODO Auto-generated method stub
//						return x*x*x-3*x*x+1;
//						return -0.2*x*x + 4;
		//				return 1/x;
						return x;
		//				return -x+1;
//						return Math.sin(x) + 0.5* Math.cos(x);
		//				return 1.5*x;
					}
				};
				
				double[][] hanshupointf = MathPointUtil.hanshupoint(hanshu,0,Math.PI*2);
				zhi.add(hanshupointf);
				
				
				HanShu fourier_jishu2hanshu = Fourier_jishu2hanshu(100, 1, hanshu, 0, Math.PI*2);
				double[][] asa = MathPointUtil.hanshupoint(fourier_jishu2hanshu);
				zhi.add(asa);
				
				double hanshu2 = fourier_jishu2hanshu.hanshu(1);
				
				List<double[][]> drawpoint_x = MathPointUtil.drawpoint_x(1, hanshu2);
				System.out.println(hanshu2);
				zhi.addAll(drawpoint_x);
		
				
				
				
		//
		//		double hanshu = fourier_jishu2hanshu.hanshu(0.24);
		//		System.out.println(hanshu);
				
				
		//		double[] hangshuhuoqu = MathUtils.hangshuhuoqu(x, y);
		//		for (int i = 0; i < hangshuhuoqu.length; i++) {
		//			System.out.println(hangshuhuoqu[i]);
		//		}
		//		HanShu hangshuhuoqu2hanshu = MathUtils.hangshuhuoqu2hanshu(hangshuhuoqu);
		//		double[][] hanshupointMathUtils = MathPointUtil.hanshupoint(hangshuhuoqu2hanshu);
		//		zhi.add(hanshupointMathUtils);
				
		//		Double[][] chazhi1 = C.chazhi1(x, y, 8.4);
		//		System.out.println(chazhi1);
		//		HanShu chazhi12hanshu = C.chazhi12hanshu(chazhi1);
		//		double[][] hanshupointMathUtils = MathPointUtil.hanshupoint(chazhi12hanshu);
		//		zhi.add(hanshupointMathUtils);
		return zhi;
	}


	
	
	
	
	
	
	
	
	
	
	/**
	 * 三角函数叠加测试
	 * @return
	 */
	private static List<double[][]> testnorm() {
		List<double[][]> zhi = new ArrayList<double[][]>();//函数的线簇

		HanShu hanShu = new HanShu() {
			
			@Override
			public double hanshu(double t, double x) {
				// TODO Auto-generated method stub
				return x;
			}
			
			@Override
			public double hanshu(double x) {
				// TODO Auto-generated method stub
				return 4*Math.sin(x*(2*Math.PI))/Math.PI + 4*Math.sin(x*(2*Math.PI)*3)/(3*Math.PI)
						+4*Math.sin(x*(2*Math.PI)*5)/(5*Math.PI) + 4*Math.sin(x*(2*Math.PI)*7)/(7*Math.PI) ;
				
			}
		};
		double[][] hanshupoint = MathPointUtil.hanshupoint(hanShu);
		zhi.add(hanshupoint);
		
		
		
		return zhi;
	}

	
	
	
	/**
	 * 通过级数的长度、角频率、拟合函数，起始点，起始点到结束点的增量
	 * 得到一个傅里叶级数的拟合函数
	 * 
	 * 这种直接拟合函数的，其实在性能上还是有弱点的，还有一种方法，叫快速傅里叶变换，我是在不同时间不同地点接触
	 * 到它，但现在还是不知道那玩意干嘛的，这个东西还涉及到复数领域
	 * 
	 * @param n	级数的长度
	 * @param w	角频率 我认为可以默认设置为1	角频率和周期变动要联合变动		w/T=1/2*Math.PI这个比例
	 * @param hanshu 需要拟合的函数
	 * @param t0 x开始的位置
	 * @param T	t0+T是x结束的位置，T就是起始点到结束点的增量	这里默认是2*Math.PI		角频率和周期变动要联合变动w/T=1/2*Math.PI这个比例
	 * @return
	 */
	public static HanShu Fourier_jishu2hanshu(final int n,final double w,HanShu hanshu,double t0,double T) {
		final double a0 = jishuget_an_one(t0, T, w, hanshu, 0);
		
		
		final double[] a = jishuget_an(t0, T, w, hanshu, n);
		final double[] b = jishuget_bn(t0, T, w, hanshu, n);
		
		HanShu result = new HanShu() {
			
			@Override
			public double hanshu(double t, double x) {
				// TODO Auto-generated method stub
				return 0;
			}
			
			@Override
			public double hanshu(double x) {
				// TODO Auto-generated method stub
				return jishu(n, a0, a, b, w, x);
			}
		};
		return result;
		
		
		
//		return null;
	}
	
	
	
	
	
	
	
	
	
	/**
	 * 傅里叶级数
	 * 任意画一段周期函数，我们可以先将它用插值方式来得到一个函数在这一段周期的函数方程
	 * 然后用这个函数方程代入到傅里叶级数中来，这样完整的傅里叶级数方程就可以了
	 * 
	 * @param n
	 * @param a0
	 * @param a
	 * @param b
	 * @param w
	 * @param t
	 */
	public static double jishu(int n,double a0,double a[],double b[],double w,double x) {
		
		double result = a0/2;
		for (int i = 0; i < n; i++) {
			
			result += a[i]*Math.cos((i+1)*w*x) + b[i]*Math.sin((i+1)*w*x);
			
		}
		return result;	
	}
	
	
	
	/**
	 * a1到an
	 * @param n
	 * @return
	 */
	public static double[] jishuget_an(double t0,double T,final double w,final HanShu hanshu,int n) {
		double a[] = new double[n];
		
		for (int i = 1; i <= n; i++) {
			
			double jishuget_an_one = jishuget_an_one(t0, T, w, hanshu, i);

			a[i-1] = jishuget_an_one;
			
		}

		
		return a;
		
	}
	
	
	
	/**
	 * b1到bn
	 * @param t0
	 * @param T
	 * @param w
	 * @param hanshu
	 * @param n
	 * @return
	 */
	public static double[] jishuget_bn(double t0,double T,final double w,final HanShu hanshu,int n) {
		double b[] = new double[n];
		
		for (int i = 1; i <= n; i++) {
			
			double jishuget_bn_one = jishuget_bn_one(t0, T, w, hanshu, i);

			b[i-1] = jishuget_bn_one;
			
		}
		
		return b;
		
	}
	
	
	
	
	/**
	 * 傅里叶级数 每一个ai的计算
	 * @param t0
	 * @param T
	 * @param w
	 * @param hanshu
	 * @param n
	 * @return
	 */
	public static double jishuget_an_one(double t0,double T,final double w,final HanShu hanshu,final int n) {
		
		HanShu hanshuresult = new HanShu() {
			
			@Override
			public double hanshu(double t, double x) {
				// TODO Auto-generated method stub
				return 0;
			}
			
			@Override
			public double hanshu(double x0) {
				// TODO Auto-generated method stub
				return hanshu.hanshu(x0)*Math.cos(n*w*x0);
			}
		};
		
		double hanshujifen = Calculate.hanshujifen2(t0, t0+T, hanshuresult);
//		double jifen1 = D.jifen1(t0, t0+T, 1000, hanshuresult);
//		System.out.println(hanshujifen+"内部的积分" + n);
		
		return (2*hanshujifen)/T;
	}
	
	/**
	 * 傅里叶级数 每一个bi的计算
	 * @param t0
	 * @param T
	 * @param w
	 * @param hanshu
	 * @param n
	 * @return
	 */
	public static double jishuget_bn_one(double t0,double T,final double w,final HanShu hanshu,final int n) {
		
		HanShu hanshuresult = new HanShu() {
			
			@Override
			public double hanshu(double t, double x) {
				// TODO Auto-generated method stub
				return 0;
			}
			
			@Override
			public double hanshu(double x0) {
				// TODO Auto-generated method stub
				return hanshu.hanshu(x0)*Math.sin(n*w*x0);
			}
		};
		
		double hanshujifen = Calculate.hanshujifen2(t0, t0+T, hanshuresult);

//		double jifen1 = D.jifen1(t0, t0+T, 1000, hanshuresult);
		
		
		return (2*hanshujifen)/T;
	}
	
	

}
